use alloc::format;
use alloc::string::String;
use core::mem;
use core::ptr::null_mut;
use core::time::Duration;

pub fn now() -> Duration {
    unsafe {
        let mut tv: libc::timeval = core::mem::zeroed();
        libc::gettimeofday(&mut tv, null_mut());
        Duration::from_millis(tv.tv_sec as u64 * 1000 + tv.tv_usec as u64 / 1000)
    }
}

pub fn hw_now() -> Duration {
    unsafe {
        let mut spec: libc::timespec = mem::zeroed();

        if libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut spec) == 0 {
            Duration::from_millis(spec.tv_sec as u64 * 1000 + spec.tv_nsec as u64 / 1000_000)
        } else {
            now()
        }
    }
}

pub enum DateTimeFormat {
    YYYYMMDDhhmmss,
    YYYYMMDDhhmmssCompat,
}

pub struct DateTime {}

impl DateTime {
    pub fn format(ts_sec: u64, fmt: DateTimeFormat, is_utc: bool) -> String {
        unsafe {
            let time = ts_sec as libc::time_t;
            let tm = if is_utc {
                &*libc::gmtime(&time)
            } else {
                &*libc::localtime(&time)
            };
            match fmt {
                DateTimeFormat::YYYYMMDDhhmmss => {
                    format!(
                        "{:04}-{:02}-{:02} {:02}:{:02}:{:02}",
                        tm.tm_year + 1900,
                        tm.tm_mon + 1,
                        tm.tm_mday,
                        tm.tm_hour,
                        tm.tm_min,
                        tm.tm_sec
                    )
                }
                DateTimeFormat::YYYYMMDDhhmmssCompat => {
                    format!(
                        "{:04}{:02}{:02}{:02}{:02}{:02}",
                        tm.tm_year + 1900,
                        tm.tm_mon + 1,
                        tm.tm_mday,
                        tm.tm_hour,
                        tm.tm_min,
                        tm.tm_sec
                    )
                }
            }
        }
    }
}
